package com.pz.gulimall.order.config;

import com.pz.gulimall.common.exception.BizCodeEnum;
import com.pz.gulimall.common.exception.RRException;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.concurrent.ListenableFutureCallback;

import java.util.HashMap;
import java.util.Map;

import static com.pz.gulimall.common.constant.MQConstant.orderReleaseOtherRoutingKey;

@Configuration
@Slf4j
public class MQConfig implements ApplicationContextAware {
    public static final String orderFinnishRoutingKey = "order.finish.#";
    public static final String orderFinnishUserQueName = "order.finnish.user.que";
    public static final String orderFinnishWareQueName = "order.finnish.ware.que";

    /**
     *生产者可靠性配置
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        RabbitTemplate rabbitTemplate = applicationContext.getBean(RabbitTemplate.class);

        //设置发送消息确认的回调
//        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
//            log.info("消息发送确认回调--correlationData-{}, ack-{}， cause-{}", correlationData, ack, cause);
//            if (!ack) {
//                // TODO 消息没有发送到MQ服务器，存储到数据库
//            }
//            if(correlationData != null) {
//                correlationData.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {
//                    @Override
//                    public void onFailure(@NotNull Throwable ex) {
//                        log.error("handle msg ack error--{}", ex.getMessage());
//                    }
//
//                    @Override
//                    public void onSuccess(CorrelationData.Confirm result) {
//                        if(result.isAck()){
//                            log.info("发送消息成功");
//                        } else {
//                            log.error("发送消息失败，原因-{}", result.getReason());
//                        }
//                    }
//                });
//            }
//        });

        //设置消息抵达队列的确认回调（消息没有抵达指定队列的时候回调）
        rabbitTemplate.setReturnsCallback(returned ->
            {
                log.error("消息发送失败 >>> 应答码-{}, 原因-{}, 交换机-{}, 路由-{}, 消息-{}",
                        returned.getReplyCode(), returned.getReplyText(), returned.getExchange(), returned.getRoutingKey(), returned.getMessage());
                // TODO 消息没有发送到Que，存储消息到服务器
                throw new RRException(BizCodeEnum.ORDER_MESSAGE_SENDEXCEPTION.getMsg()+returned.getReplyText(), BizCodeEnum.ORDER_MESSAGE_SENDEXCEPTION.getCode());
            }
        );
    }

    /**
     * 绑定库存释放队列 stock.release.que 用于取消订单时主动通知库存服务释放库存
     */
    @Bean
    public Binding bindReleaseOther() {
        return new Binding("stock.release.que", Binding.DestinationType.QUEUE, orderEventExchangeName, orderReleaseOtherRoutingKey, null);
    }


    /**------------------------------------  延时队列配置 ------------------------------------------------**/
    public static final String orderReleaseQueName = "order.release.que";
    public static final String orderEventExchangeName = "orderEvent.exchange";
    private static final String deadLetterRoutingKey = "order.release.order";
    public static final String orderCreateRoutingKey = "order.create.order";
    private static final String orderDelayQueName = "order.delay.que";
    @Value("${delayTime}")
    private Long delayTime;

    /**
     * 死信交换机
     */
    @Bean
    public Exchange orderEventExchange(){
        return new TopicExchange(orderEventExchangeName, true, false);
    }

    /**
     * 死信延迟队列
     */
    @Bean
    public Queue orderDelayQue(){
        Map<String, Object> arguments = new HashMap<>();
        //设置消息属性
        arguments.put("x-dead-letter-exchange", orderEventExchangeName);   // 消息到期要发送的 交换机
        arguments.put("x-dead-letter-routing-key", deadLetterRoutingKey);  // 消息到期要发送的 路由key
        arguments.put("x-message-ttl", delayTime);
        return new Queue(orderDelayQueName, true, false, false, arguments);
    }

    /**
     * 提供给外界访问的队列，接收死信消息
     */
    @Bean
    public Queue orderReleaseQue(){
        return new Queue(orderReleaseQueName, true, false, false);
    }

    /**
     * 死信队列绑定
     */
    @Bean
    public Binding orderReleaseOrderBinding() {
        return new Binding(orderReleaseQueName, Binding.DestinationType.QUEUE, orderEventExchangeName, deadLetterRoutingKey,null);
    }

    /**
     * 延迟队列绑定(创建订单的 路由)
     */
    @Bean
    public Binding orderDelayOrderBinding() {
        return new Binding(orderDelayQueName, Binding.DestinationType.QUEUE, orderEventExchangeName, orderCreateRoutingKey, null);
    }

    /**------------------------------------  延时队列配置 ------------------------------------------------**/
}
